<?php

// Prevent individual file access
if(!defined('DIR_BASE')) exit;

/**
 * Easy and fast querybuilder
 */
class QueryBuilder {
	
	/**
	 * Constants for private use (CRUD)
	 */
	const SELECT = 1;
	const INSERT = 2;
	const UPDATE = 3;
	const DELETE = 4;
	
	/**
	 * Contains one of the constants above
	 */
	protected $qType = 0;
	
	/**
	 * For selecting which columns to return
	 */
	protected $qColumns = array();
	
	/**
	 * The 'WHERE' clause presented as a string
	 */
	protected $qWhere = '';
	
	/**
	 * The 'JOIN' clause
	 */ 
	protected $qJoin = array();
	
	/**
	 * The 'ORDER BY' clause presented as a string
	 */
	protected $qOrder = '';
	
	/**
	 * Tables to perform actions in
	 */	
	protected $qTables = array();
	
	/**
	 * For insert/update purposes
	 */
	protected $qSets = array();
	
	/**
	 * For limiting a resultset
	 */
	protected $qLimit = '';
	
	/**
	 * The query that has been build
	 */
	protected $qry = '';
	
	/**
	 * Select from table(s) with specified columns, if not given then select all columns (*)
	 */
	public function select(){
		$this->qType = self::SELECT;
		$args = func_get_args();
		foreach($args as $arg){
			if(is_string($arg))
				$this->qColumns[] = $arg;
		}
		return $this;
	}
	
	/**
	 * Insert record in table
	 */
	public function insert(){
		$this->qType = self::INSERT;
		return $this;
	}
	
	/**
	 * Update table records
	 */
	public function update(){
		$this->qType = self::UPDATE;
		return $this;
	}
	
	/**
	 * Delete table records
	 */
	public function delete(){
		$this->qType = self::DELETE;
		return $this;
	}
	
	/**
	 * Set specified column to specified value in a INSERT/UPDATE clause
	 * @param String $column The columnname to take affect
	 * @param String $value The value it has to be set to
	 */
	public function set($column, $value = ''){
		if(is_array($column)){
			foreach($column as $key => $value){
				$this->qSets[] = $key.' = \''.$value.'\'';
			}
		}else
			$this->qSets[] = $column.' = \''.$value.'\'';
		
		return $this;
	}
	public function increase($column, $value = 0){
		$this->qSets[] = $column.' = '.$column.' + '.$value;
		return $this;
	}
	public function decrease($column, $value = 0){
		$this->qSets[] = $column.' = '.$column.' - '.$value;
		return $this;
	}
	
	/**
	 * Set specified tablename to perform actions to
	 * @param String $table The tablename
	 * @param String $alias Give the table an alias for further use
	 */
	public function table($table, $alias = ''){
		if(!empty($alias))
			$table .= ' AS '.$alias;
		$this->qTables[] = $table;
		return $this;
	}
	
	/**
	 * Set the where clause
	 */
	public function where($where){
		$args = func_get_args();
		if(isset($args[1]))
			$where .= ' = \''.$args[1].'\'';
		
		$this->qWhere .= $where;
		return $this;
	}
	/**
	 * Add 'AND' operator (used for the where-clause)
	 */
	public function andd(){
		$this->qWhere .= ' AND ';
		return $this;
	}
	/**
	 * Add 'OR' operator (used for the where-clause)
	 */
	public function orr(){
		$this->qWhere .= ' OR ';
		return $this;
	}
	
	/**
	 * Join table
	 */
	public function join($table, $alias, $tablecol, $othercol){
		$this->qJoin[] = $table.' AS '.$alias.' ON '.$tablecol.' = '.$othercol;
		return $this;
	}
	
	/**
	 * Sort the result
	 */
	public function orderby($col){
		$this->qOrder = $col;
		return $this;
	}
	
	/**
	 * Set a limit
	 * @param Int $offset (optional) Where to start counting records
	 * @param Int $length The number of records to show
	 */
	public function limit($length = 0){
		$offset = 0;		
		$args = func_get_arguments();
		if(sizeof($args) == 2){
			$offset = $args[0];
			$length = $args[1];
		}
		if(!empty($length)){
			$this->qLimit = $offset.','.$length;
		}
	}
	
	/**
	 * Build the actual query and clean-up all variables
	 * @return String A query code
	 */
	public function build(){
		// skip if no tables has been given
		if(empty($this->qTables))
			return false;
		
		$qry = '';
		switch($this->qType){
			case self::SELECT:{
				$qry .= 'SELECT ';
				if(!empty($this->qColumns))
					$qry .= implode(', ', $this->qColumns);
				else{
					$qry .= '*';
				}
				$qry .= ' FROM '.implode(', ', $this->qTables);
				if(!empty($this->qJoin))
					$qry .= ' INNER JOIN '.implode(' INNER JOIN ', $this->qJoin);
				if(!empty($this->qWhere))
					$qry .= ' WHERE '.$this->qWhere;
				if(!empty($this->qOrder))
					$qry .= ' ORDER BY '.$this->qOrder;
				if(!empty($this->qLimit))
					$qry .= ' LIMIT '.$this->qLimit;
				break;
			}
			case self::UPDATE:{
				$qry .= 'UPDATE ';
				$qry .= implode(', ', $this->qTables);
				if(!empty($this->qSets))
					$qry .= ' SET '.implode(', ', $this->qSets);
				// skip if there is nothing to set to
				else return false;
				
				if(!empty($this->qWhere))
					$qry .= ' WHERE '.$this->qWhere;
				if(!empty($this->qLimit))
					$qry .= ' LIMIT '.$this->qLimit;
				break;
			}
			case self::INSERT:{
				$qry .= 'INSERT INTO ';
				$qry .= $this->qTables[0];
				if(!empty($this->qSets))
					$qry .= ' SET '.implode(', ', $this->qSets);
				// skip if there is nothing to set to
				else return false;
				break;
			}
			case self::DELETE:{
				$qry .= 'DELETE FROM ';
				$qry .= $this->qTables[0];
				if(!empty($this->qWhere))
					$qry .= ' WHERE '.$this->qWhere;
				if(!empty($this->qLimit))
					$qry .= ' LIMIT '.$this->qLimit;
				break;
			}
		}
		
		// clean-up variables
		$this->qType = 0;
		$this->qColumns = array();
		$this->qCreates = array();
		$this->qWhere = '';
		$this->qJoin = array();
		$this->qTables = array();
		$this->qSets = array();
		$this->qLimit = '';
		
		// save query
		$this->qry = $qry;
		return $qry;
	}
}

?>